from django.contrib.auth import login, authenticate, logout
from django.db import DatabaseError
from django.shortcuts import render, redirect
from django.urls import reverse
from django.views import View
from django import http
from django.contrib.auth.mixins import LoginRequiredMixin
from django_redis import get_redis_connection
import re, json, logging

from carts.utils import merge_carts_cookies_redis
from goods.models import SKU
from users.models import User, Address
from meiduo_mall.utils.response_code import RETCODE
from meiduo_mall.utils.views import LoginRequiredJsonMixin
from celery_tasks.email.tasks import send_verify_email
from users.utils import generate_verify_email_url, check_verify_email_token
from . import constants

# 注册日志文件
logger = logging.getLogger("django")


class UserBrowseHistory(LoginRequiredJsonMixin, View):
    """用户最近浏览记录"""
    def post(self, request):
        """保存浏览记录"""
        json_str = request.body.decode()
        json_dict = json.loads(json_str)
        sku_id = json_dict.get('sku_id')

        try:
            SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return http.HttpResponseForbidden('参数sku_id错误')

        # 保存sku_id到redis
        redis_conn = get_redis_connection('history')
        user = request.user
        pl = redis_conn.pipeline()
        # 先去重(删除已存在的)
        pl.lrem('history_%s' % user.id, 0, sku_id)
        # 再保存：最近在最前
        pl.lpush('history_%s' % user.id, sku_id)
        # 最后截取
        pl.ltrim('history_%s' % user.id, 0, 4)
        # 执行
        pl.execute()

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})

    def get(self, request):
        """查询浏览记录"""
        user = request.user
        redis_conn = get_redis_connection('history')
        # 取出列表数据
        sku_ids = redis_conn.lrange('history_%s' % user.id, 0, -1)  #（0, 4）
        # 将模型转字典
        skus = []
        for sku_id in sku_ids:
            sku = SKU.objects.get(id=sku_id)
            skus.append({
                'id': sku.id,
                'name': sku.name,
                'price': sku.price,
                'default_image_url': sku.default_image.url
            })

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'skus': skus})


# 用户注册
class RegisterView(View):

    def get(self, request):
        return render(request, "register.html")

    def post(self, request):
        # 获取表单数据
        username = request.POST.get("username")
        password = request.POST.get("password")
        password2 = request.POST.get("password2")
        mobile = request.POST.get("mobile")
        allow = request.POST.get("allow")
        sms_code = request.POST.get("sms_code")

        # 判空
        if not all([username, password, password2, mobile, allow, sms_code]):
            return http.HttpResponseForbidden("缺少必传参数")
        # 判断数据是否符合定义需求
        if not re.match(r'^[a-zA-Z0-9-_]{5,20}', username):
            return http.HttpResponseForbidden("请输入5-20个字符的用户名")

        if not re.match(r'^[a-zA-Z0-9]{8,20}$', password):
            return http.HttpResponseForbidden("请输入8-20个字符密码")

        if password != password2:
            return http.HttpResponseForbidden("两次输入的密码不相同")

        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden("请输入正确的手机号码")

        if allow != "on":
            return http.HttpResponseForbidden("请勾选用户协议")

        # 判断短信验证码
        redis_connect = get_redis_connection("verify_code")
        sms_code_server = redis_connect.get("sms %s" % mobile)
        if sms_code_server is None:
            return render(request, "register.html", {"sms_code_error": "无效验证码"})
        if sms_code != sms_code_server.decode("utf-8"):
            return render(request, "register.html", {"sms_code_error": "输入的短信验证码有误"})

        # 写入数据到数据库
        try:
            user = User.objects.create_user(username=username, password=password, mobile=mobile)
        # 错误返回
        except DatabaseError:
            render(request, "register.html", {'register_errmsg': '注册失败'})
        # 写入session
        login(request, user)
        # 响应注册结果
        response = redirect(reverse("contents:index"))
        # 注册时写入cookie
        response.set_cookie("username", user.username, max_age=3600)
        return response


# 校验用户名
class UsernameContView(View):
    def get(self, request, username):
        # 查询数据
        count = User.objects.filter(username=username).count()
        # 返回数据
        return http.JsonResponse({"code": RETCODE.OK, "errmsg": "OK", "count": count})


# 校验手机号
class MobileView(View):
    def get(self, request, mobile):
        # 查询数据
        count = User.objects.filter(mobile=mobile).count()
        # 返回数据
        return http.JsonResponse({"code": RETCODE.OK, "errmsg": "OK", "count": count})


# 用户登陆
class LoginView(View):

    def get(self, request):
        return render(request, "login.html")

    def post(self, request):
        username = request.POST.get("username")
        password = request.POST.get("password")
        remembered = request.POST.get("remembered")
        if not all([username, password]):
            return http.HttpResponseForbidden("缺少必传参数")
        if not re.match(r'^[a-zA-Z0-9-_]{5,20}', username):
            return http.HttpResponseForbidden("请输入正确的手机号或用户名")
        if not re.match(r'^[a-zA-Z0-9]{8,20}$', password):
            return http.HttpResponseForbidden("密码最少8位, 最长20位")
        # 校验用户登陆
        user = authenticate(username=username, password=password)

        if user is None:
            return render(request, "login.html", {"account_errmsg": "用户或密码错误"})
        login(request, user)
        if remembered != "on":
            # 没有记住用户
            request.session.set_expiry(0)
        else:
            request.session.set_expiry(3600)
        # 判断用户是否直接选择用户中心
        next = request.GET.get("next")
        if next:
            # 重定向到next
            response = redirect(next)
        else:
            # 重定向到首页
            response = redirect(reverse("contents:index"))
        # 登陆时写入cookie：response.set_cookie('key', 'value', 'expiry')
        response.set_cookie("username", user.username, max_age=3600)
        # 用户登陆成功，合并cookie购物车到redis购物车
        response = merge_carts_cookies_redis(request=request, user=user, response=response)
        # 响应结果
        return response


# 退出登陆
class LogoutView(View):
    def get(self, request):
        logout(request)
        response = redirect(reverse("contents:index"))
        response.delete_cookie("username")
        return response


# 展示用户中心界面
class UserInfoView(LoginRequiredMixin, View):
    def get(self, request):
        context = {
            "username": request.user.username,
            "mobile": request.user.mobile,
            "email": request.user.email,
            "email_active": request.user.email_active
        }
        return render(request, "user_center_info.html", context)


# 添加邮箱
class EmailView(LoginRequiredJsonMixin, View):
    def put(self, request):
        json_data = json.loads(request.body.decode("utf-8"))
        email = json_data.get("email")
        if email is None:
            return http.HttpResponseForbidden("缺少必传参数")
        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return http.HttpResponseForbidden("参数email不符合要求")

        # 将email 数据写入到数据库
        try:
            request.user.email = email
            request.user.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({"code": RETCODE.DBERR, "errmsg": "添加邮箱失败"})

        # 异步发送邮件验证
        verify_url = generate_verify_email_url(request.user)
        send_verify_email.delay(email, verify_url)

        return http.JsonResponse({"code": RETCODE.OK, "errmsg": "添加邮箱成功"})


# 验证邮箱
class VerifyEmailView(View):
    def get(self, request):
        token = request.GET.get("token")
        if token is None:
            return http.HttpResponseBadRequest("缺少token")  # 不明白这个返回对象
        # 获取user
        user = check_verify_email_token(token)
        if user is None:
            return http.HttpResponseBadRequest("无效的token")

        # 修改email_active为True
        try:
            user.email_active = True
            user.save()
        except Exception as e:
            logger.error(e)
            return http.HttpResponseServerError("激活邮箱失败")
        return redirect(reverse("users:info"))


# 用户收货地址
class AddressView(LoginRequiredMixin, View):
    def get(self, request):
        login_user = request.user
        try:
            addresses = Address.objects.filter(user=login_user, is_delete=False)

            # 序列化
            address_dict_list = []
            for address in addresses:
                address_dict = {
                    "id": address.id,
                    "title": address.title,
                    "receiver": address.receiver,
                    "province": address.province.name,
                    "city": address.city.name,
                    "district": address.district.name,
                    "place": address.place,
                    "mobile": address.mobile,
                    "tel": address.tel,
                    "email": address.email
                }
                address_dict_list.append(address_dict)

            context = {
                # "default_address_id": request.user.default_address_id,
                "default_address_id": request.user.default_address_id or '0',
                "addresses": address_dict_list
            }
        except Exception as e:
            logger.error(e)
            return http.HttpResponseForbidden("显示信息失败")

        return render(request, "user_center_site.html", context)


# 新增收货地址
class CreateAddressView(LoginRequiredJsonMixin, View):
    def post(self, request):
        # 判断地址数量  / 需要加一个判断的条件
        count = request.user.addresses.filter(is_delete=False).count()
        if count > constants.USER_ADDRESS_COUNTS_LIMIT:
            return http.JsonResponse({"code": RETCODE.THROTTLINGERR, "errmsg": "超过地址的数量"})
        # 接收数据
        json_data = json.loads(request.body.decode("utf-8"))
        receiver = json_data.get("receiver")
        province_id = json_data.get("province_id")
        city_id = json_data.get("city_id")
        district_id = json_data.get("district_id")
        place = json_data.get("place")
        mobile = json_data.get("mobile")
        tel = json_data.get("tel")
        email = json_data.get("email")

        # 判断数据
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return http.HttpResponseForbidden("缺少必传参数")
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden("手机号格式错误")
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.HttpResponseForbidden("固定电话格式错误")
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseForbidden("邮箱格式错误")
        # 保存收货地址
        try:
            address = Address.objects.create(user=request.user,
                                             title=receiver,
                                             receiver=receiver,
                                             province_id=province_id,
                                             city_id=city_id,
                                             district_id=district_id,
                                             place=place,
                                             mobile=mobile,
                                             tel=tel,
                                             email=email)
            if request.user.default_address is None:
                request.user.default_address = address
                request.user.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({"code": RETCODE.DBERR, "errmsg": "新增收货地址失败"})
        address_dict = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }
        return http.JsonResponse({"code": RETCODE.OK, "errmsg": "新增收货地址成功", "address": address_dict})


# 修改和删除地址
class UpdateDestroyAddressView(LoginRequiredJsonMixin, View):
    def put(self, request, address_id):
        # 接收数据
        json_data = json.loads(request.body.decode("utf-8"))
        receiver = json_data.get("receiver")
        province_id = json_data.get("province_id")
        city_id = json_data.get("city_id")
        district_id = json_data.get("district_id")
        place = json_data.get("place")
        mobile = json_data.get("mobile")
        tel = json_data.get("tel")
        email = json_data.get("email")

        # 判断数据
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return http.HttpResponseForbidden("缺少必传参数")
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden("手机号格式错误")
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.HttpResponseForbidden("固定电话格式错误")
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseForbidden("邮箱格式错误")
        # 判断数据是否存在，并更新信息
        try:
            Address.objects.filter(id=address_id).update(
                user=request.user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email
            )
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({"code": RETCODE.DBERR, "errmsg": "更新信息失败"})
        # 创建响应数据
        try:
            address = Address.objects.get(id=address_id)
            address_dict = {
                "id": address.id,
                "title": address.title,
                "receiver": address.receiver,
                "province": address.province.name,
                "city": address.city.name,
                "district": address.district.name,
                "place": address.place,
                "mobile": address.mobile,
                "tel": address.tel,
                "email": address.email
            }
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({"code": RETCODE.DBERR, "errmsg": "响应数据失败"})

        return http.JsonResponse({"code": RETCODE.OK, "errmsg": "更新信息成功", "address": address_dict})

    def delete(self, request, address_id):
        try:
            # 查询要删除的地址
            adderss = Address.objects.get(id=address_id)
            # 逻辑删除地址
            adderss.is_delete = True
            adderss.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({"code": RETCODE.DBERR, "errmsg": "删除信息失败"})

        return http.JsonResponse({"code": RETCODE.OK, "errmsg": "删除信息成功"})


# 设为默认地址
class DefaultAddressView(LoginRequiredJsonMixin, View):
    def put(self, request, address_id):
        try:
            address = Address.objects.get(id=address_id)
            request.user.default_address = address
            request.user.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({"code": RETCODE.DBERR, "errmsg": "设置默认地址失败"})
        return http.JsonResponse({"code": RETCODE.OK, "errmsg": "设置默认地址成功"})


# 修改地址标题
class UpdateTitleAddressView(LoginRequiredJsonMixin, View):
    def put(self, request, address_id):
        json_data = json.loads(request.body.decode("utf-8"))
        title = json_data.get("title")
        if not title:
            return http.JsonResponse({"code": RETCODE.DBERR, "errmsg": "title不可为空"})
        try:
            address = Address.objects.get(id=address_id)
            # 设置默认标题
            address.title = title
            address.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({"code": RETCODE.DBERR, "errmsg": "地址标题更新失败"})
        return http.JsonResponse({"code": RETCODE.OK, "errmsg": "地址标题更新成功"})


# 修改密码
class ChangePasswordView(LoginRequiredMixin, View):

    def get(self, request):
        return render(request, "user_center_pass.html")

    def post(self, request):
        # 接收参数
        old_password = request.POST.get("old_password")
        new_password = request.POST.get("new_password")
        new_password2 = request.POST.get("new_password2")
        # 校验参数
        if not all([old_password, new_password, new_password2]):
            return http.HttpResponseForbidden("缺少必传参数")
        # 原始密码和数据库做比对
        if not request.user.check_password(old_password):
            return render(request, "user_center_pass.html", {"origin_password_errmsg": "原始密码错误"})
        # 校验新密码
        if not re.match(r'^[0-9A-Za-z]{8,20}$', new_password):
            return http.HttpResponseForbidden("密码短8位， 最长20位")
        if new_password != new_password2:
            return http.HttpResponseForbidden("两次输入密码不一致")
        # 修改密码
        try:
            request.user.set_password(new_password)
            request.user.save()
        except Exception as e:
            logger.error(e)
            return render(request, "user_center_pass.html", {"change_password_errmsg": "修改密码失败"})
        # 清除记录
        logout(request)
        response = redirect(reverse("users:login"))
        response.delete_cookie("username")
        return response